package tester;

import java.util.ArrayList;
//import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

//import src.Bond;
//import src.BondsBruteForce;
import src.BondsViaUpperNeigbors;
import src.ClosureType;
import src.Concept;
import src.MultifunctionComparisonException;
//import src.ClosureType;
import src.Context;

public class StudentsSchoolsTester {

	public static void main(String[] args) {
//		Double[][] relation1 = {{ 1.0, 0.5, 0.5, 1.0, 1.0 },			
//								{ 1.0, 1.0, 1.0, 1.0, 0.5 },
//								{ 0.0, 0.0, 0.5, 0.5, 1.0 }};
//
//		Double[][] relation2 = {{ 0.5, 0.0, 0.0 },			
//								{ 0.5, 0.0, 0.5 },
//								{ 1.0, 1.0, 1.0 },
//								{ 0.5, 0.5, 0.0 },
//								{ 0.0, 0.0, 0.0 }};
		
		Double[][] relation1 = {{ 0.0, 1.0, 0.5, 0.5, 0.5 },			
					{ 0.0, 0.5, 0.5, 1.0, 1.0 }};

		Double[][] relation2 = {{ 1.0, 1.0, 0.5, 1.0 },			
				{ 1.0, 1.0, 1.0, 0.5 },
				{ 1.0, 0.5, 0.0, 1.0 }};
		
//		BondsBruteForce b = new BondsBruteForce(relation1, relation2, ClosureType.UP_DOWN, 3);
//		
//		System.out.println("BONDs");
//		System.out.println();		
//		
//		System.out.println("bonds from extent variations");
//		System.out.println();
//		
//		int i = 0;
//		for (Bond bond : b.getBondsFromExtentPointOfView()) {
//			System.out.println(++i + ": " + bond);
//		}
//		System.out.println();
//		
//		System.out.println("bonds from intent variations");
//		System.out.println();	
//		
//		i = 0;
//		for (Bond bond : b.getBondsFromIntentPointOfView()) {
//			System.out.println(++i + ": " + bond);
//		}
//		System.out.println();
	
		Context c1 = new Context(3, relation1);
		Context c2 = new Context(3, relation2);		
		BondsViaUpperNeigbors bonds = new BondsViaUpperNeigbors(c1, c2);
		
		bonds.latticeOfBonds();
		
		Map<List<List<Double>>, Map<Character, Set<List<List<Double>>>>> latticeOfBonds = bonds.getLatticeOfBonds();
		int i = 0;
		for (List<List<Double>> bond : latticeOfBonds.keySet()) {
			System.out.println(++i + ". " + bond);
			
			System.out.println("\tupper neighbors:");
			Set<List<List<Double>>> upperNeigbors = latticeOfBonds.get(bond).get('u');
			if (upperNeigbors != null) {
				for (List<List<Double>> upperNeigbor : upperNeigbors) {
					System.out.println("\t" + upperNeigbor);
				}	
			}
			System.out.println();			
			System.out.println("\tlower neighbors:");
			Set<List<List<Double>>> lowerNeigbors = latticeOfBonds.get(bond).get('l');
			for (List<List<Double>> lowerNeigbor : lowerNeigbors) {
				System.out.println("\t" + lowerNeigbor);	
			}
			System.out.println();
		}
		
		System.out.println("---------------------------------------------------------------");
		
		Set<List<List<Double>>> setOfBonds = latticeOfBonds.keySet();
		List<List<List<Double>>> supIrreducibles = new ArrayList<List<List<Double>>>();
		List<List<List<Double>>> infIrreducibles = new ArrayList<List<List<Double>>>();
		
//		TODO: zahrnat aj tie ktore nemaju dolneho/horneho suseda? 
//		supremum irreducible		
		System.out.println("supremum irreducible");
		i = 0;
		for (List<List<Double>> bond : setOfBonds) {
			
			if (latticeOfBonds.get(bond).get('l').size() <= 1) {
				System.out.println(++i + ". " + bond);
				for (List<List<Double>> lowerNeighbor : latticeOfBonds.get(bond).get('l')) {
					System.out.println("\t" + lowerNeighbor);
				}
				System.out.println();
				
				supIrreducibles.add(bond);
			}
		}
		
//		infimum irreducible
		System.out.println("infimum irreducible");
		i = 0;
		for (List<List<Double>> bond : setOfBonds) {

			if (latticeOfBonds.get(bond).get('u').size() <= 1) {
				System.out.println(++i + ". " + bond);
				for (List<List<Double>> upperNeighbor : latticeOfBonds.get(bond).get('u')) {
					System.out.println("\t" + upperNeighbor);
				}
				System.out.println();
				
				infIrreducibles.add(bond);
			}
		}
		
		List<List<Double>> naturallySmallContext = new ArrayList<List<Double>>();
		
		for (int j = 0; j < supIrreducibles.size(); j++) {
			naturallySmallContext.add(new ArrayList<Double>());
			for (int k = 0; k < infIrreducibles.size(); k++) {
				naturallySmallContext.get(j).add(0.0);
			}
		}
		
		for (int j = 0; j < supIrreducibles.size(); j++) {			
			for (int k = 0; k < infIrreducibles.size(); k++) {
				for (List<Double> row : supIrreducibles.get(j)) {
					System.out.println("sup. " + (j + 1) + ": " + row);
				}
				System.out.println();
				for (List<Double> row : infIrreducibles.get(k)) {
					System.out.println("inf. " + (k + 1) + ": " + row);
				}
				System.out.println(isLowerNeighbor(supIrreducibles.get(j), infIrreducibles.get(k)));
				System.out.println();
		
				if (isLowerNeighbor(supIrreducibles.get(j), infIrreducibles.get(k))) {
					naturallySmallContext.get(j).set(k, 1.0);
				}			
			}
		}
		
		for (List<Double> row : naturallySmallContext) {
			System.out.println(row);
		}
		System.out.println();
		
		System.out.println("Naturally small context for lattice of bonds of given L-context");
		
		naturallySmallContext = bonds.getNaturallySmallContext();
		for (List<Double> row : naturallySmallContext) {
			System.out.println(row);
		}	
		System.out.println();
		
		Context c = new Context(2, naturallySmallContext); 
		c.lattice(ClosureType.UP_DOWN);
		
//		check if concept lattice of naturally small context is isomorphic to lattice of bonds
		System.out.println("Concepts of naturally small context");
		Set<Concept> concepts = c.getConcepts();
		for (Concept concept : concepts) {
			System.out.println(concept);
		}
		System.out.println();
		
		System.out.println(c.getConcepts().size());
	}
	
	private static boolean isLowerNeighbor(List<List<Double>> multiFunction1, List<List<Double>> multiFunction2) {
		
		if (multiFunction1.size() != multiFunction2.size()) {
			throw new MultifunctionComparisonException("You are not allowed to compare multifunctions with different number of objects");
		}
		
		if (multiFunction1.get(0).size() != multiFunction2.get(0).size()) {
			throw new MultifunctionComparisonException("You are not allowed to compare multifunctions with different number of attributes");
		}
		
		for (int i = 0; i < multiFunction1.size(); i++) {
			for (int j = 0; j < multiFunction2.size(); j++) {
				if (multiFunction1.get(i).get(j) > multiFunction2.get(i).get(j)) {
					return false;
				}
			}
		}		
		return true;
	}
}